package com.kly.test.function.home.viewmodel

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.paging.DataSource
import androidx.paging.PagedList
import androidx.paging.toLiveData
import com.kly.test.base.BaseVMViewModel
import com.kly.test.base.adpater.Cell
import com.kly.test.base.adpater.ID_MORE_LOADING
import com.kly.test.base.adpater.ID_NO_MORE
import com.kly.test.base.adpater.LoadStatus
import com.kly.test.base.adpater.PAGE_INITIAL
import com.kly.test.base.adpater.PageDataSource
import com.kly.test.base.adpater.add
import com.kly.test.base.adpater.addAll
import com.kly.test.base.adpater.isRefreshing
import com.kly.test.base.adpater.mutablePutAll
import com.kly.test.base.adpater.remove
import com.kly.test.base.adpater.safelySubList
import com.kly.test.base.adpater.superProcessCell
import com.kly.test.model.HomeListDataBean
import com.kly.test.util.runOnUIThread
import com.kly.test.util.runOnWorkThread
import kotlin.math.max
import kotlin.math.min

data class HomeState(
    val page: Int = PAGE_INITIAL,
    val list: List<String> = listOf(),//保存所有的ID
    val data: Map<String, HomeListDataBean> = mapOf(),//数据存储
    val loading: LoadStatus = LoadStatus.IDLE
) {
    companion object {
        const val ID_DAILY_INCOME_LIST = "ID_DAILY_INCOME_LIST"
    }
}

class HomeViewModel : BaseVMViewModel() {

    val loading = MutableLiveData<LoadStatus>()
    var indexState = HomeState()
    var indexDataSource: PageDataSource? = null
    val dataList = mutableListOf<HomeListDataBean>()

    val dataAllList = indexDataSoureFactory()
        .toLiveData(
            pageSize = 20,
            boundaryCallback = object : PagedList.BoundaryCallback<Cell>() {
                override fun onItemAtEndLoaded(itemAtEnd: Cell) {
                    if (ID_MORE_LOADING == itemAtEnd.id) {
                        reqIndexList(false)
                    }
                }
            }
        )

    //请求数据
    fun reqIndexList(initial: Boolean) {
        runOnWorkThread { internalRequestIndexList(initial) }
    }


    private fun internalRequestIndexList(initial: Boolean) {
        //先虚拟请求一波数据
        if (indexState.loading.isRefreshing()) return
        reducing(initial)
        val nextPage = if (initial) PAGE_INITIAL else (indexState.page + 1)
        for (i in 1..10) {
            val item = HomeListDataBean().copy(
                head = "https://pics3.baidu.com/feed/9f510fb30f2442a7676e975c1ab2ad45d31302e2.jpeg@f_auto?token=196b549ff3a0fb524e4ee0f9932eab70",
                nickname = "Maryam Mitchell, $i",
                requestId = "$i"
            )
            dataList.add(item)
        }
        reducingResult(initial, dataList)
    }

    private fun reducingResult(initial: Boolean, data: List<HomeListDataBean>) {

        if (initial) {
            if (data.isNullOrEmpty()) {

            } else {
                //不为空的情况
                val actuallyFetchOver = data.size < 20
                var preList = data.map { it.requestId.toString() }

                preList =
                    if (actuallyFetchOver) preList.add(ID_NO_MORE) else preList.add(ID_MORE_LOADING)

                indexState = indexState.let {
                    it.copy(
                        page = PAGE_INITIAL,
                        list = preList,
                        data = it.data.mutablePutAll(data.map {
                            Pair(
                                it.requestId.toString(),
                                it
                            )
                        }),
                        loading = LoadStatus.SUCCESS
                    )
                }
            }
        } else {
            indexState = if (data.isEmpty()) {
                indexState.let {
                    it.copy(
                        page = PAGE_INITIAL,
                        list = it.list.remove(ID_MORE_LOADING).add(ID_NO_MORE)
                    )
                }
            } else {
                val actuallyFetchOver = data.size < 20

                indexState.let {
                    it.copy(
                        page = it.page + 1,
                        list = it.list.remove(ID_MORE_LOADING).addAll(data.map {
                            it.requestId.toString()
                        }).let {
                            if (actuallyFetchOver) it.add(ID_NO_MORE) else it.add(ID_MORE_LOADING)
                        },
                        data = it.data.mutablePutAll(
                            data.map {
                                Pair(it.requestId.toString(), it)
                            }
                        )
                    )
                }
            }
        }
        Log.i("IndexFragment", "IndexViewModel reducingResult $indexState")
        notifyStateInvalidate()
    }

    private fun reducing(initial: Boolean) {
        if (initial) {
            indexState = indexState.copy(loading = LoadStatus.LOADING)
            loading.postValue(indexState.loading)
        }
    }

    private fun notifyStateInvalidate() {
        indexDataSource?.invalidate()
        if (loading.value != indexState.loading) {
            runOnUIThread {
                loading.value = indexState.loading
            }
        }
    }

    private fun indexDataSoureFactory(): DataSource.Factory<Int, Cell> =
        object : DataSource.Factory<Int, Cell>() {
            override fun create(): DataSource<Int, Cell> {
                return object : PageDataSource() {
                    override fun totalCount(): Int {
                        return indexState.list.size
                    }

                    override fun loadRange(start: Int, count: Int): List<Cell?> {
                        val list = indexState.list
                        return list.safelySubList(max(0, start), min(list.size, start + count))
                            .map {
                                superProcessCell(it)
                                    ?: Cell(
                                        ItemType.HomeListData,
                                        it,
                                        extra = indexState.data[it]
                                    )
                            }
                    }
                }.also {
                    indexDataSource = it
                }
            }
        }

}

class HomeViewModelModelFactory : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(HomeViewModel::class.java)) {
            return HomeViewModel() as T
        }
        //noinspection unchecked
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}